package com.zc.serveudpdemo;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import com.zc.serveudpdemo.callback.DeviceObserver;
import com.zc.serveudpdemo.utils.AToast;
import com.zc.serveudpdemo.utils.FiFoUsbStream;
import com.zc.serveudpdemo.utils.LogUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * 功能描述：Usb连接管理类
 *
 * @author：ZC 创建时间：2019/5/28 8:44
 * 最后修改日期：
 */
public class UsbConnectStatus {

    private static final String TAG = UsbConnectStatus.class.getSimpleName();
    private Context mContext;
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    public static final int USB_CONNECTED = 0;
    public static final int USB_DISCONNECT = 1;
    public static final int SDK_VERSION_ABOVE = 26;
    /**
     * USB管理器
     */
    private UsbManager manager;
    /**
     * 找到的USB设备
     */
    private UsbDevice mUsbDevice = null;
    private UsbDeviceConnection mDeviceConnection;
    /**
     * 节点
     */
    private UsbEndpoint epOut;
    private UsbEndpoint epInUsbStream;

    private int UsbStatus = USB_DISCONNECT;
    private FiFoUsbStream fiFoUsbStream;
    private FileOutputStream outUsbStream = null;
    private boolean isRecording = false;
    private ExecutorService executorService;
    private UsbStatusHandler mUsbStatusHandler;

    private List<DeviceObserver> mObserverList = new ArrayList<>();

    public void addDataObserver(DeviceObserver observer) {
        if (null != observer && !mObserverList.contains(observer)) {
            mObserverList.add(0, observer);
        }
    }

    public UsbConnectStatus(Context context) {
        this.mContext = context;
        executorService = Executors.newScheduledThreadPool(5);

        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        mContext.registerReceiver(mUsbReceiver, filter);

        fiFoUsbStream = new FiFoUsbStream();
        mUsbStatusHandler = new UsbStatusHandler();

        usbDevicesInit();
        startRevStream();
    }

    private void usbDevicesInit() {
        //获取USB设备
        manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        if (manager == null) {
            return;
        } else {
            LogUtils.i(TAG, "usb device:" + String.valueOf(manager.toString()));
        }

        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        LogUtils.i(TAG, "usb device:" + String.valueOf(deviceList.size()));
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        //存放USB设备的数量
        ArrayList<String> usbDeviceList = new ArrayList<String>();
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
            usbDeviceList.add(String.valueOf(device.getVendorId()));
            usbDeviceList.add(String.valueOf(device.getProductId()));
            // 在这里添加处理设备的代码
            if (device.getVendorId() == 0x0000
                    || device.getVendorId() == 0x04b4
                    || device.getVendorId() == 0x0951
                    || device.getVendorId() == 0x483
                    || device.getVendorId() == 0xAAAA) {
                mUsbDevice = device;
                LogUtils.i(TAG, "Found devices");
            }
        }
        findEndPoints();
    }

    private int interfaceCount = 0;
    private UsbInterface[] mInterfaceArray = new UsbInterface[5];

    private void findEndPoints() {
        if (mUsbDevice == null) {
            LogUtils.i(TAG, "Can not found usb devices!");
            return;
        }

        interfaceCount = mUsbDevice.getInterfaceCount();
        LogUtils.e(TAG, "interfaceCount is:" + interfaceCount);
        if (interfaceCount < 1) {
            return;
        }

        for (int i = 0; i < interfaceCount; i++) {
            // 获取设备接口，一般都是一个接口，你可以打印getInterfaceCount()方法查看接
            // 口的个数，在这个接口上有两个端点，OUT 和 IN
            mInterfaceArray[i] = mUsbDevice.getInterface(i);
        }

        if (mInterfaceArray[0] != null) {
            UsbDeviceConnection connection = null;
            //判断是否有权限
            PendingIntent permissionIntent = PendingIntent.getBroadcast(mContext,
                    0, new Intent(ACTION_USB_PERMISSION), 0);
            manager.requestPermission(mUsbDevice, permissionIntent);

            if (manager.hasPermission(mUsbDevice)) {
                // 打开设备，获取 UsbDeviceConnection 对象，连接设备，用于后面的通讯
                connection = manager.openDevice(mUsbDevice);
                if (connection == null) {
                    return;
                }
                mDeviceConnection = connection;
                UsbStatus = USB_CONNECTED;

                for (int i = 0; i < interfaceCount; i++) {
                    if (connection.claimInterface(mInterfaceArray[i], true)) {
                        int endpointNum = mInterfaceArray[i].getEndpointCount();
                        for (int index = 0; index < endpointNum; index++) {
                            UsbEndpoint ep = mInterfaceArray[i].getEndpoint(index);
                            LogUtils.e(TAG, "intface: " + i + "   ep Direction: "
                                    + ep.getDirection()
                                    + "getEndpointNumber:"
                                    + ep.getEndpointNumber());
                            if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                                if (ep.getEndpointNumber() == 0x06) {
                                    //usb码流（主镜头）
                                    epInUsbStream = ep;
                                }
//                                if (ep.getEndpointNumber() == 0x05) {
//                                    //hdmi码流（瞄准镜）
//                                    epInUsbStream = ep;
//                                }
                            } else if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                                if (ep.getEndpointNumber() == 0x01) {
                                    epOut = ep;
                                }
                            }
                        }
                    }
                }
            } else {
                LogUtils.e(TAG, "没有权限");
            }
        } else {
            LogUtils.i(TAG, "没有找到接口");
        }
    }

    private byte[] revUsbStream = new byte[1024];

    private void startRevStream() {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                int dataLen = 0;
                while (USB_CONNECTED == UsbStatus) {
                    try {
                        dataLen = mDeviceConnection.bulkTransfer(epInUsbStream, revUsbStream, revUsbStream.length, 300);
                        if (dataLen > 0) {
                            if (outUsbStream != null && isRecording) {
                                outUsbStream.write(revUsbStream, 0, dataLen);
                            }
                            fiFoUsbStream.FiFoWrite(revUsbStream, dataLen);
                            reportReceivedUsbStream(fiFoUsbStream);
                        }
                    } catch (Exception e) {
                        LogUtils.e(TAG, "Capture usb stream error!!!");
                    }
                }
            }
        });
    }

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                LogUtils.e(TAG, "usb ACTION_USB_PERMISSION");
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent
                            .getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(
                            UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            //Maybe use in the future
                            LogUtils.e(TAG, "BroadcastReceiver ACTION_USB_PERMISSION");
                        }
                    } else {
                        LogUtils.d(TAG, "permission denied for device " + device);
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                LogUtils.e(TAG, "Detecting the usb remove " + UsbStatus + "    " + interfaceCount);
                synchronized (this) {
                    if (USB_CONNECTED == UsbStatus) {
                        Message msg = mUsbStatusHandler.obtainMessage();
                        msg.what = 100;
                        mUsbStatusHandler.sendMessage(msg);
                        UsbStatus = USB_DISCONNECT;
                        for (int i = 0; i < interfaceCount; i++) {
                            LogUtils.e(TAG, "Detecting the usb remove   check " + i);
                            boolean result = mDeviceConnection.releaseInterface(mInterfaceArray[i]);
                            LogUtils.e(TAG, "releaseInterface result is:" + result);
                        }
                        for (int i = 0; i < interfaceCount; i++) {
                            mInterfaceArray[i] = null;
                        }
                        mDeviceConnection.close();
                        mDeviceConnection = null;
                        mUsbDevice = null;

                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                LogUtils.e(TAG, "Detecting the usb adding");
                synchronized (this) {
                    if (USB_DISCONNECT == UsbStatus) {
                        Message msg = mUsbStatusHandler.obtainMessage();
                        msg.what = 101;
                        mUsbStatusHandler.sendMessage(msg);
                        UsbStatus = USB_CONNECTED;
                    }
                }
            }
        }
    };

    private class UsbStatusHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            try {
                switch (msg.what) {
                    case 100:
                        AToast.init(mContext, "USB断开连接");
                        break;
                    case 101:
                        AToast.init(mContext, "USB已连接");
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void startSave() {
        try {
            SimpleDateFormat format = new SimpleDateFormat(
                    "yyyy-MM-dd-HH-mm-ss");
            String currentTime = format.format(new Date());
            String savePath = Environment.getExternalStorageDirectory()
                    .getAbsolutePath()
                    + "/SavedFile_"
                    + currentTime
                    + ".264";

            File file = new File(savePath);
            if (file.isFile() && file.exists()) {
                file.delete();
            }
            outUsbStream = new FileOutputStream(file);
            isRecording = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void stopSave() {
        try {
            outUsbStream.close();
            outUsbStream = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        isRecording = false;
    }


    private void reportReceivedUsbStream(FiFoUsbStream fiFoUsbStream) {
        for (DeviceObserver observer : mObserverList) {
            if (observer != null) {
                observer.onUsbStream(fiFoUsbStream);
            }
        }
    }

    /**
     * 移除指定观察者
     *
     * @param observer 被移除的对象
     */
    public void removeObserver(DeviceObserver observer) {
        if (mObserverList.contains(observer)) {
            mObserverList.remove(observer);
        }
    }

    public void destroy() {
        if (USB_CONNECTED == UsbStatus) {
            UsbStatus = USB_DISCONNECT;
            for (int i = 0; i < interfaceCount; i++) {
                mDeviceConnection.releaseInterface(mInterfaceArray[i]);
            }
        }
        System.exit(0);
        executorService.shutdown();
        mContext.unregisterReceiver(mUsbReceiver);
    }

}
